/*
 * Copyright 2010 (c) Dou Yongwang (douyongwang@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include "sjson.h"


namespace sjson {

_LIT8(kTrue, "true");
_LIT8(kFalse, "false");
_LIT8(kNull, "null");
_LIT8(kMinus, "-");
_LIT8(kPlus, "+");
_LIT8(kCurlyBraceL, "{");
_LIT8(kCurlyBraceR, "}");
_LIT8(kColon, ":");
_LIT8(kComma, ",");
_LIT8(kSquareBracketL, "[");
_LIT8(kSquareBracketR, "]");

void Dump(const CJSONValue& /*aValue*/)
	{

	}

int utf8_char_length(TUint8* lead_it)
	{
	TUint8 lead = 0xFF & (*lead_it);
    if (lead < 0x80)
        return 1;
    else if ((lead >> 5) == 0x6)
        return 2;
    else if ((lead >> 4) == 0xe)
        return 3;
    else if ((lead >> 3) == 0x1e)
        return 4;
    else
        return 0;
    }

void unicodecvt(TDes8& aDes, int iUnicode)
	{
	if (iUnicode < 0x0080)
		{// character 0x0000 - 0x007f...
		aDes.Append(0x00 | ((iUnicode & 0x007f) >> 0));
		}
	else if (iUnicode < 0x0800)
		{
		// character 0x0080 - 0x07ff...
		aDes.Append(0xc0 | ((iUnicode & 0x07c0) >> 6));
		aDes.Append(0x80 | ((iUnicode & 0x003f) >> 0));
		}
	else
		{
		// character 0x0800 - 0xffff...
		aDes.Append(0xe0 | ((iUnicode & 0x00f000) >> 12));
		aDes.Append(0x80 | ((iUnicode & 0x000fc0) >>  6));
		aDes.Append(0x80 | ((iUnicode & 0x00003f) >>  0));
		}
	}

static int hex2int(char c)
{
  if(c >= '0' && c <= '9')
    return c - '0';
  if(c >= 'A' && c <= 'F')
    return c - 'A' + 10;
  if(c >= 'a' && c <= 'f')
    return c - 'a' + 10;
  return -1;
}

char* int2hexstr(int n, char* buf)
	{
//	static char INT2HEX[16] = "0123456789abcdef";
	static char INT2HEX[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
	'a', 'b', 'c', 'd', 'e', 'f'};
	#define int2hex(X) INT2HEX[(X)&0xf]
    char* ptr = buf + 5;
    *--ptr = 0;
	*--ptr = int2hex(n); n >>= 4;
	*--ptr = int2hex(n); n >>= 4;
	*--ptr = int2hex(n); n >>= 4;
	*--ptr = int2hex(n);
	return ptr;
	}

HBufC8* DecodeJSONString(const TDesC8& aData)
	{
    HBufC8* ret = HBufC8::New(aData.Length());
    if (ret)
    	{
		TPtr8 ptr = ret->Des();
		const TUint8* p = aData.Ptr();
		const TUint8* pend = p+ aData.Length();
		while (p<pend)
			{
			if (*p != '\\')
				{
				ptr.Append(*p);
				}
			else
				{
				++p;
				switch (*p)
					{
					default:   { ptr.Append(*p); break; }
	//				case '\/': { ptr.Append('/'); break; }
	//				case '\"': { ptr.Append('\"'); break; }
					case 'b' : { ptr.Append('\b'); break; }
					case 'f' : { ptr.Append('\f'); break; }
					case 'n' : { ptr.Append('\n'); break; }
					case 'r' : { ptr.Append('\r'); break; }
					case 't' : { ptr.Append('\t'); break; }
					case 'u' :
						{
						// 2.1.2.1: convert the following hex value into an int...
						int iUnicode = hex2int(*(p+1)) << 12 |
									   hex2int(*(p+2)) << 8 |
									   hex2int(*(p+3)) << 4 |
									   hex2int(*(p+4));
						// 2.1.2.2: append the unicode int...
						unicodecvt(ptr, iUnicode);
						p+=4;
						break;
						}
					}
				}
			++p;
			}
    	}
    return ret;
	}
#define mask8(x) (0xFF&(x))
HBufC8* EncodeJSONString(const TDesC8& aData, TBool aEnclose)
	{
	const TInt kPadding = 12;		// 12 means two encoded json unicode chars(6 bytes for each one)
	TInt maxlen = aData.Length() + kPadding;
    HBufC8* ret = HBufC8::New(maxlen);
    if (ret)
    	{
		//Reference: http://www.unicode.org/versions/Unicode5.1.0/
		TPtr8 ptr = ret->Des();
		if (aEnclose)
			ptr.Append('\"');
		const TUint8* p = aData.Ptr();
		const TUint8* pend = p + aData.Length();
		while (p<pend)
			{
			if (maxlen <= ptr.Length() + kPadding)
				{
				maxlen += maxlen / 2;	// this will add more buffer(at least 6 bytes)
				ret = ret->ReAlloc(maxlen);
			    if (!ret)
			    	return ret;
//				ptr = ret->Des();	// !!!WARN: do not use this. use the below one instead.
				ptr.Set(ret->Des());
				}
			switch(*p)
				{
				case '"' : { ptr.Append(_L8("\\\"")); break; }
				case '\\': { ptr.Append(_L8("\\\\")); break; }
				case '\b': { ptr.Append(_L8("\\b")); break; }
				case '\f': { ptr.Append(_L8("\\f")); break; }
				case '\n': { ptr.Append(_L8("\\n")); break; }
				case '\r': { ptr.Append(_L8("\\r")); break; }
				case '\t': { ptr.Append(_L8("\\t")); break; }
				case '/' : { ptr.Append(_L8("\\/")); break; }
				default:
					{
					int cp = mask8(*p);
					TInt len = utf8_char_length((TUint8*)p);
					switch (len)
						{
						case 1: { ptr.Append(*p); break;}
		                case 2:
		                	{
		                    ++p;
		                    cp = ((cp << 6) & 0x7ff) + ((*p) & 0x3f);
		                    break;
		                	}
		                case 3:
		                	{
		                    ++p;
		                    cp = ((cp << 12) & 0xffff) + ((mask8(*p) << 6) & 0xfff);
		                    ++p;
		                    cp += (*p) & 0x3f;
		                    break;
		                	}
		                default:
		                	{
		                	break;
		                	}
#if 0
		                case 4:
		                	{
		                	// never goes here.
		                    ++p;
		                    cp = ((cp << 18) & 0x1fffff) + ((mask8(*p) << 12) & 0x3ffff);
		                    ++p;
		                    cp += (mask8(*p) << 6) & 0xfff;
		                    ++p;
		                    cp += (*p) & 0x3f;
		                    break;
		                	}
#endif
						}
					if (len > 1)
						{
						char buf[5];
						int2hexstr(cp, buf);
						TPtrC8 v((TUint8*)buf, 4);
						ptr.Append(_L8("\\u"));
						ptr.Append(v);
						}
					}
				}
			++p;
			}
		if (aEnclose)
			ptr.Append('\"');
    	}
	return ret;
	}

TInt SkipWhitespaces(const TDesC8& aInput)
	{
    TInt i=0;
    TInt len = aInput.Length();
    while (i < len)
    	{
    	if (aInput[i] == ' ' || aInput[i] == '\r' || aInput[i] == '\n' || aInput[i] == '\t')
    		++i;
    	else
    		break;
    	}
    return i;
    }

// Try to consume characters from the input stream and match the
// pattern string. Leading whitespaces from the input are ignored if
// ignore_ws is true.
TInt MatchPattern(const TDesC8& aPattern, const TDesC8& aInput, TBool aIgnoreWs = ETrue)
	{
	TInt len = 0;
    if (aIgnoreWs)
    	{
    	len = SkipWhitespaces(aInput);
    	}
	if (aInput.Length() - len < aPattern.Length())
		return KErrNotFound;

	const TPtrC8& token = aInput.Mid(len, aPattern.Length());
	if (token.Compare(aPattern) == 0)
		return (len + aPattern.Length());

	return KErrNotFound;
	}

TInt ParseRawData(const TDesC8& aInput, TPtrC8& aValue)
	{
    TInt pos = 0;
//	if (aInput[0] == ' ' || aInput[0] == '\r' || aInput[0] == '\n' || aInput[0] == '\t')
//		return -1;

    TBool needExit = EFalse;

    TInt embedLevel = 0;
	TLex8 lex(aInput.Mid(pos));
	lex.Mark();
	while (!lex.Eos())
		{
		switch (lex.Peek())
			{
			case '(':
				{
			    ++embedLevel;
				break;
				}
			case ')':
				{
				--embedLevel;
				break;
				}
			case ',':
			case ']':
			case '}':
				{
				if (embedLevel == 0)
					needExit = ETrue;
				break;
				}
			case '\\':
				{
				lex.Inc();
//				if (lex.Peek() == '\"')
//					++embedLevel
				break;
				}
#if 0
				// TODO: support 
			case '\"':
			case '\'':
				{
				embedLevel++;
				break;
				}
#endif
			}
		if (needExit) break;
		lex.Inc();
		}
	aValue.Set(lex.MarkedToken());

	// skip
//	lex.Inc();

    return (pos + lex.Offset());
	}

TInt ParseString(const TDesC8& aInput, TPtrC8& aValue, const TDesC8& aQuoteChar)
	{
    TInt pos = MatchPattern(aQuoteChar, aInput);
    if (pos < 0)
    	return pos;
#if 0
    TInt len = aInput.Length();
    if (pos <= len)
    	{
    	TPtrC8 ptr = aInput.Mid(pos);
    	TInt nextQuote = ptr.Locate(kDoubleQuote()[0]);
    	if (nextQuote < 0)
    		return nextQuote;

    	aValue.Set(ptr.Mid(0, nextQuote));
    	pos += nextQuote;
    	pos += kDoubleQuote().Length();
    	return pos;
    	}
#else
    TBool fFound = EFalse;
    
    TChar quoteChar = aQuoteChar[0];

    TInt embedLevel = 0;
	TLex8 lex(aInput.Mid(pos));
	lex.Mark();
	while (!lex.Eos())
		{
		switch (lex.Peek())
			{
			case '{':
			case '[':
				{
			    ++embedLevel;
				break;
				}
			case ']':
			case '}':
				{
				--embedLevel;
				break;
				}
			case '\\':
				{
				lex.Inc();
//				if (lex.Peek() == '\"')
//					++embedLevel
				break;
				}
#if 0
#ifndef USE_SINGLE_QUOTE
			case '\"':
#else
			case '\'':
#endif
#else
			default:
#endif
				{
				if (lex.Peek() == aQuoteChar[0] && embedLevel == 0)
					fFound = ETrue;
				break;
				}
			}
		if (fFound) break;
		lex.Inc();
		}
	aValue.Set(lex.MarkedToken());

	// skip
	lex.Inc();
#endif
    return (pos + lex.Offset());
	}

TInt ParseBool(const TDesC8& aInput, TBool& aValue)
	{
	TInt pos = MatchPattern(kTrue, aInput);
    if (pos != KErrNotFound)  {
        aValue = ETrue;
        return pos;
    }
    pos = MatchPattern(kFalse, aInput);
    if (pos != KErrNotFound) {
        aValue = EFalse;
        return pos;
    }
    return KErrNotFound;
}

TInt ParseNull(const TDesC8& aInput)
	{
	TInt pos = MatchPattern(kNull, aInput);
    if (pos != KErrNotFound)
    	{
        return pos;
        }
    return KErrNotFound;
}

TInt ParseDouble(const TDesC8& aInput, TReal64& aValue)
	{
	TInt ret(KErrNotFound);

	TInt pos = SkipWhitespaces(aInput);
	const TPtrC8 ptr = aInput.Mid(pos);
	TLex8 lex(ptr);
	TInt sign = 1;
	if (lex.Peek() == '+')
	    {
	    lex.Inc();
	    }
	if ( lex.Peek() == '-')
		{
		sign = -1;
		lex.Inc();
		}
	// ensure we are looking at a digit or sign
	lex.Mark();
	TBool bIsDouble = EFalse;
	while (!lex.Eos())
	{
		// deal with sign
		if( lex.Peek() == '.')
			bIsDouble = ETrue;
		else if (lex.Peek() == ',' || lex.Peek() == '}')
		{
			
			ret = TLex8(lex.MarkedToken()).Val(aValue);
			if (ret == KErrNone)
			{
				TInt64 val2 = 0;
				TInt ret2 = TLex8(lex.MarkedToken()).Val(val2);
				if(ret2 == KErrNone && (((TReal64)(val2)) == aValue) && !bIsDouble)
					return -1;
				aValue *= sign;
				return (pos + lex.Offset());
			}
		break;
		}
		lex.Inc();
	}
	return ret;
	}


TInt ParseNumber(const TDesC8& aInput, TInt64& aValue)
	{
	TInt ret(KErrNotFound);

	TInt pos = SkipWhitespaces(aInput);
	const TPtrC8 ptr = aInput.Mid(pos);
	TLex8 lex(ptr);
	TInt sign = 1;
	if (lex.Peek() == '+')
	    {
	    lex.Inc();
	    }
	if ( lex.Peek() == '-')
		{
		sign = -1;
		lex.Inc();
		}
	// ensure we are looking at a digit or sign
	lex.Mark();
	while (!lex.Eos())
		{
		// deal with sign
		if (!(lex.Peek().IsDigit() || (lex.Peek() == '.') ) )
		    {
			ret = TLex8(lex.MarkedToken()).Val(aValue);
			if (ret == KErrNone)
				{
				aValue *= sign;
				return (pos + lex.Offset());
				}
			break;
		    }
		lex.Inc();
		}
	return ret;
	}

CJSONObject::CJSONObject() : iIter(iValueMap)
	{}

CJSONObject::~CJSONObject()
	{
//	iValueMap.ResetAndDestroy();
//	iValueMap.Close();
	CleanMap();
	}
void CJSONObject::CleanMap()
	{
//	RValueMap::TIter iter(iValueMap);
//	const TDesC8* key = iter.NextKey();
//	while (key)
//		{
//		CJSONValue* value = const_cast<CJSONValue*>(iter.CurrentValue());
//		delete value;
//		delete key;
//		key = iter.NextKey();
//		}
	iValueMap.ResetAndDestroy();
	iValueMap.Close();
	}

TInt CJSONObject::Parse(const TDesC8& aInput, const TDesC8& aQuoteChar)
	{
	TInt pos = MatchPattern(kCurlyBraceL, aInput);
    if (pos < 0)
    	return pos;

    do
    	{
        TPtrC8 key;
        TInt ret = ParseString(aInput.Mid(pos), key, aQuoteChar);
        if (ret < 0)  break;	// key not found.
        pos += ret;

        ret = MatchPattern(kColon, aInput.Mid(pos));
        if (ret < 0)  return ret;
        pos += ret;

        CJSONValue* v = CJSONValue::NewL();
        if (!v)
        	return KErrNoMemory;
        ret = v->Parse(aInput.Mid(pos), aQuoteChar);
        if (ret < 0)
        	{
            delete v;
            return ret;
            }
        pos += ret;
        HBufC8 * k = key.Alloc();
        if (!k)
        	{
        	delete v;
        	return KErrNoMemory;
        	}
        iValueMap.Insert(k, v);

        ret = MatchPattern(kComma, aInput.Mid(pos));
        if (ret < 0)
        	break;
        pos += ret;
    } while (1);

    TInt ret = MatchPattern(kCurlyBraceR, aInput.Mid(pos));
    if (ret < 0)
        return ret;
    pos += ret;

    return pos;
    }

TInt CJSONObject::Add(const TDesC8& aKey, CJSONValue*& aVal)
	{
	HBufC8* key = aKey.Alloc();
	if (!key)
		{
		delete aVal;
		aVal = NULL;
		return KErrNoMemory;
		}
	TInt ret = iValueMap.Insert(key, aVal);
	if (ret != KErrNone)
		{
		delete key;
		delete aVal;
		aVal = NULL;
		}
	return ret;
	}

//TInt CJSONObject::Add(const TDesC8& aKey, TInt32 aVal)
//	{
//	CJSONValue* jVal = new CJSONValue(aVal);	//
//    return Add(aKey, jVal);
//	}

TInt CJSONObject::Add(const TDesC8& aKey, TInt64 aVal)
	{
	CJSONValue* jVal = CJSONValue::NewL(aVal);	//
    return Add(aKey, jVal);
	}

TInt CJSONObject::Add(const TDesC8& aKey, TBool aVal)
	{
	CJSONValue* jVal = CJSONValue::NewL(aVal);	//
    return Add(aKey, jVal);
	}

TInt CJSONObject::Add(const TDesC8& aKey, const TDesC8& aVal)
	{
	HBufC8* val = aVal.Alloc();
	if (!val) return KErrNoMemory;
	CJSONValue* jVal = CJSONValue::NewL(val);	// ownership of val transferred.
    return Add(aKey, jVal);
	}

TInt CJSONObject::Count()
	{
	return iValueMap.Count();
	}

HBufC8* CJSONObject::ToJSONStringLC(const TDesC8& aQuoteChar) const
	{
	const TInt kExpandSize = 128;
	CBufSeg* buf = CBufSeg::NewL(kExpandSize);
	CleanupStack::PushL(buf);
	buf->InsertL(0, kCurlyBraceL);
#if 0
	RValueMap::TIter iter(iValueMap);
#else
	RValueMapIter iter(iValueMap);
#endif
	const TDesC8* key = iter.NextKey();
	while (key)
		{
		const CJSONValue* val = iter.CurrentValue();
		buf->InsertL(buf->Size(), aQuoteChar);
		buf->InsertL(buf->Size(), *key);
		buf->InsertL(buf->Size(), aQuoteChar);
		buf->InsertL(buf->Size(), kColon);
		HBufC8* v = val->ToJSONStringLC(aQuoteChar);
		buf->InsertL(buf->Size(), *v);
		CleanupStack::PopAndDestroy(v);

		key = iter.NextKey();
		if (key)
			{
			buf->InsertL(buf->Size(), kComma);
			}
		}
	buf->InsertL(buf->Size(), kCurlyBraceR);

	// Create a heap descriptor from the buffer
	HBufC8* des = HBufC8::NewL(buf->Size());
	TPtr8 ptr(des->Des());
	buf->Read(0, ptr, buf->Size());

	CleanupStack::PopAndDestroy(buf); // Finished with the buffer
	CleanupStack::PushL(des);
	return (des);
	}

TBool CJSONObject::NextKey()
	{
	const TDesC8* key = iIter.NextKey();
	return (key != 0);
	}
const TDesC8& CJSONObject::CurrentKey() const
	{
	return *iIter.CurrentKey();
	}
void CJSONObject::Reset()
	{
	iIter.Reset();
	}
CJSONValue* CJSONObject::GetL(const TDesC8& aKey)
	{
	return iValueMap.Find(aKey);
	}


//
// CJSONValue implementation
//

CJSONValue::CJSONValue() : iType(EInvalid) {}

CJSONValue::~CJSONValue()
	{
	reset();
    }

TInt CJSONValue::Parse(const TDesC8& aInput, const TDesC8& aQuoteChar)
	{
	reset();
//	if (aInput.Length() == 0)
//		return KErrNone;
	// parse string value
    TPtrC8 stringValue;
    TInt pos = ParseString(aInput, stringValue, aQuoteChar);
    if (pos > 0)
    	{
        iStringValue = DecodeJSONString(stringValue);
        if (!iStringValue)
        	return KErrNoMemory;
        iType = EString;
        return pos;
        }

	pos = ParseDouble(aInput, iDouble64Value);
    if (pos > 0){
    	iType = EDouble64;
    	return pos;	
    }
    
    // parse int value
    pos = ParseNumber(aInput, iInt64Value);
    if (pos > 0) {
        iType = EInt64;
        return pos;
    }

    // parse bool value
    pos = ParseBool(aInput, iBoolValue);
    if (pos > 0) {
        iType = EBool;
        return pos;
    }

    // parse null value
    pos = ParseNull(aInput);
    if (pos > 0) {
        iType = ENull;
        return pos;
    }
    // parse array value
    iArrayValue = CJSONArray::NewL();
    pos = iArrayValue->Parse(aInput, aQuoteChar);
    if (pos > 0) {
        iType = EArray;
        return pos;
    }
    delete iArrayValue;
    iArrayValue = 0;
    // parse object value
    iObjectValue = CJSONObject::NewL();
    if (!iObjectValue)
    	return KErrNoMemory;
    pos = iObjectValue->Parse(aInput, aQuoteChar);
    if (pos > 0) {
        iType = EObject;
        return pos;
    }
    delete iObjectValue;
    iObjectValue = NULL;
#if 1
    // a fix for 
    TPtrC8 rawValue;
    pos = ParseRawData(aInput, rawValue);
    if (pos > 0)
    	{
		iRawData = rawValue.Alloc();
        if (!iRawData)
        	return KErrNoMemory;
        iType = ERawData;
        return pos;
        }
#endif
    return KErrNotFound;
}

HBufC8* CJSONValue::ToJSONStringLC(const TDesC8& aQuoteChar) const
	{
//	if (iType == EInteger || iType == EInt64)
//		{
//		TBuf8<32> buf;
//		buf.AppendNum(iIntegerValue);
//		return buf.AllocLC();
//		}
	if (iType == EInt64)
		{
		TBuf8<64> buf;
		buf.AppendNum(iInt64Value);
		return buf.AllocLC();
		}
	if (iType == EBool)
		{
		return iBoolValue ? kTrue().AllocLC() : kFalse().AllocLC();
		}
	if (iType == EString)
		{
#if 0
		HBufC8* buf = HBufC8::NewLC((*iStringValue).Length() + 2);
		TPtr8 ptr = buf->Des();
		ptr.Append('\"');
		ptr.Append(*iStringValue);
		ptr.Append('\"');
//		CleanupStack::Pop(buf);
#else
		HBufC8* buf = EncodeJSONString(*iStringValue, ETrue);
		User::LeaveIfNull(buf);
		CleanupStack::PushL(buf);
#endif
		return buf;
		}
	if (iType == ENull)
		{
		return kNull().AllocLC();
		}
	if (iType == EArray)
		{
		return iArrayValue->ToJSONStringLC(aQuoteChar);
		}
	if (iType == EObject)
		{
		return iObjectValue->ToJSONStringLC(aQuoteChar);
		}
	return KNullDesC8().AllocLC();
	}


//
// CJSONArray implementation
//


CJSONArray::CJSONArray()
	{}

CJSONArray::~CJSONArray()
	{
	iValues.ResetAndDestroy();
	iValues.Close();
	}

TInt CJSONArray::Parse(const TDesC8& aInput, const TDesC8& aQuoteChar)
	{
	TInt pos = MatchPattern(kSquareBracketL, aInput);
    if (pos < 0) return pos;

    do {
        CJSONValue* v = CJSONValue::NewL();
        if (!v)
        	return KErrNoMemory;
        TInt ret = v->Parse(aInput.Mid(pos), aQuoteChar);
        if (ret < 0) {
            delete v;
//            return ret;
            break;
        }
        pos += ret;
        ret = iValues.Append(v);
        if (ret != KErrNone)
        	return ret;

        ret = MatchPattern(kComma, aInput.Mid(pos));
        if (ret < 0)
            break;
        pos += ret;

    } while(1);

    {
    TInt ret = MatchPattern(kSquareBracketR, aInput.Mid(pos));
    if (ret < 0)
        return ret;
    pos += ret;
    }

    return pos;
    }

HBufC8* CJSONArray::ToJSONStringLC(const TDesC8& aQuoteChar) const
	{
	const TInt kExpandSize = 128;
	CBufSeg* buf = CBufSeg::NewL(kExpandSize);
	CleanupStack::PushL(buf);
	buf->InsertL(0, kSquareBracketL());
	TInt count = iValues.Count();
	for (TInt i=0; i<count; )
		{
		HBufC8* val = iValues[i]->ToJSONStringLC(aQuoteChar);
		buf->InsertL(buf->Size(), *val);
		CleanupStack::PopAndDestroy();

		if (++i < count)
			buf->InsertL(buf->Size(), kComma());
		}
	buf->InsertL(buf->Size(), kSquareBracketR);
	// Create a heap descriptor from the buffer
	HBufC8* des = HBufC8::NewL(buf->Size());
	TPtr8 ptr(des->Des());
	buf->Read(0, ptr, buf->Size());

	CleanupStack::PopAndDestroy(buf);
	CleanupStack::PushL(des);
	return des;
	}

CJSONObject* CJSONObject::NewL()
	{
	return new (ELeave) CJSONObject();
	}
CJSONArray* CJSONArray::NewL()
	{
	return new (ELeave) CJSONArray();
	}

/////////////////////////////
// CJSONValue
//
CJSONValue* CJSONValue::NewL()
	{
	return new (ELeave) CJSONValue();
	}

CJSONValue* CJSONValue::NewL(TInt64 aInt64Value)
	{
	return new (ELeave) CJSONValue(aInt64Value);
	}
CJSONValue* CJSONValue::NewL(HBufC8* aTDesC8Value)		// ownership transferred
	{
	return new (ELeave) CJSONValue(aTDesC8Value);
	}
CJSONValue* CJSONValue::NewL(TBool aBoolValue)
	{
	return new (ELeave) CJSONValue(aBoolValue);
	}
CJSONValue* CJSONValue::NewL(CJSONArray* aArrValue)			// ownership transferred
	{
	return new (ELeave) CJSONValue(aArrValue);
	}
CJSONValue* CJSONValue::NewL(CJSONObject* aObCJSONValue)		// ownership transferred
	{
	return new (ELeave) CJSONValue(aObCJSONValue);
	}
void CJSONValue::reset()
	{
    if (iType == EString)
    	{
        delete iStringValue;
        }
    if (iType == EObject)
    	{
        delete iObjectValue;
        }
    if (iType == EArray)
    	{
        delete iArrayValue;
        }
    if (iType == ERawData)
    	{
		delete iRawData;
    	}
    iType = EInvalid;
    iInt64Value = 0;
    iDouble64Value = 0.0;
	}

} // sjson

